#include "myStdio.h"

_FILE* _fopen(const char* path, const char* mode)
{
    assert(path && mode);

    int flags = 0; //打开文件的方式

    if (strcmp(mode, "r") == 0)
    {
        flags |= O_RDONLY;
    }
    else if (strcmp(mode, "w") == 0)
    {
        flags = flags | O_WRONLY | O_CREAT | O_TRUNC;
    }
    else if (strcmp(mode, "a") == 0)
    {
        flags = flags | O_WRONLY | O_CREAT | O_APPEND;
    }
    else
    {
        const char* errorMessage = "Not this way to open the file";
        write(1, errorMessage, strlen(errorMessage));
        return NULL;
    }

    int defaultAuthority = 0666; //创建文件时的默认权限
    int fd = 0;

    fd = flags & O_RDONLY 
        ? open(path, flags) //如果是r模式
        : open(path, flags, defaultAuthority); //如果是w或a模式

    if (fd < 0) //打开文件失败
    {
        const char* errorMessage = strerror(errno);
        write(1, errorMessage, strlen(errorMessage));
        return NULL;
    }

    _FILE* fp = (_FILE*)malloc(sizeof(_FILE));
    assert(fp);

    fp->flags = SYNC_LINE; //默认设置为行刷新
    fp->fileno = fd;
    fp->capacity = BUFFER_SIZE;
    fp->size = 0;
    memset(fp->buffer, 0, BUFFER_SIZE);

    return fp;
}

void _fclose(_FILE* fp)
{
    assert(fp);

    //关闭文件需要刷新缓冲区
    _fflush(fp);

    int ret = close(fp->fileno);
    if(ret == -1)
    {
        const char* errorMessage = strerror(errno);
        write(1, errorMessage, strlen(errorMessage));
        exit(errno);
    }
}

void _fflush(_FILE* fp)
{
    assert(fp);

    if(fp->size != 0)
    {
        int ret = write(fp->fileno, fp->buffer, fp->size);
        assert(ret != -1);
        fp->size = 0;
        ret = fsync(fp->fileno); //强制OS刷新文件缓冲区
        assert(ret != -1);
    }
}

//fwrite与其说是写入函数 倒不如说是拷贝函数 是将数据拷贝到缓冲区
void _fwrite(const void* ptr, size_t num, _FILE* fp)
{
    assert(ptr && fp);

    //将数据拷贝到缓冲区
    memcpy((char*)fp->buffer + fp->size, ptr, num);

    //判断是否刷新缓冲区
    if(fp->flags & SYNC_NOW)
    {
        write(fp->fileno, fp->buffer, fp->size);
        fp->size = 0;
    }
    else if(fp->flags & SYNC_LINE)
    {
        if(fp->buffer[fp->size - 1] == '\n') //abcd\nefg这种中间带\n不考虑
        {
            write(fp->fileno, fp->buffer, fp->size);
            fp->size = 0;
        }
    }
    else if(fp->flags & SYNC_FULL)
    {
        if(fp->size == fp->capacity)
        {
            write(fp->fileno, fp->buffer, fp->size);
            fp->size == 0;
        }
    }
    else
    {
        const char* errorMessage = "Bug?";
        write(1, errorMessage, strlen(errorMessage));
    }
}